home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / programm.ing / progem.lzh / apndx10.prf < prev    next >
Encoding:
Text File  |  1987-06-23  |  14.3 KB  |  568 lines

  1. .!****************************************************************************
  2. .! 
  3. .! ANTIC PUBLISHING INC., COPYRIGHT 1985.  REPRINTED BY PERMISSION.
  4. .!
  5. .! ** Professional GEM ** by Tim Oren
  6. .!
  7. .! Proff File by ST enthusiasts at
  8. .! Case Western Reserve University
  9. .! Cleveland, Ohio
  10. .! uucp : decvax!cwruecmp!bammi
  11. .! csnet: bammi@case
  12. .! arpa : bammi%case@csnet-relay
  13. .! compuserve: 71515,155
  14. .!
  15. .!****************************************************************************
  16. .!
  17. .!            Begin Appendix 10
  18. .!
  19. .!***************************************************************************
  20. .!
  21. .!
  22. .AP X Sample Code for Part XIII
  23. #include "portab.h"                /* portable coding conv    */
  24. #include "machine.h"                /* machine depndnt conv    */
  25. #include "obdefs.h"                /* object definitions    */
  26. #include "gembind.h"                /* gem binding structs    */
  27. #include "taddr.h"
  28.  
  29. #define    M1_ENTER    0x0000
  30. #define    M1_EXIT        0x0001
  31.  
  32. #define BS    0x0008
  33. #define    TAB    0x0009
  34. #define    CR    0x000D
  35. #define ESC    0x001B
  36. #define    BTAB    0x0f00
  37. #define    UP    0x4800
  38. #define    DOWN    0x5000
  39. #define    DEL    0x5300
  40.                     /* Global variables used by */
  41.                     /* 'mapped' functions        */
  42. MLOCAL    GRECT    br_rect;        /* Current break rectangle  */
  43. MLOCAL    WORD    br_mx, br_my, br_togl;    /* Break mouse posn & flag  */ 
  44. MLOCAL    WORD    fn_obj;            /* Found tabable object        */
  45. MLOCAL    WORD    fn_last;        /* Object tabbing from        */
  46. MLOCAL    WORD    fn_prev;        /* Last EDITABLE obj seen   */
  47. MLOCAL    WORD    fn_dir;            /* 1 = TAB, 0 = BACKTAB        */
  48.  
  49. /************* Utility routines for new forms manager ***************/
  50.  
  51.     VOID
  52. objc_toggle(tree, obj)            /* Reverse the SELECT state */
  53.     LONG    tree;            /* of an object, and redraw */
  54.     WORD    obj;            /* it immediately.        */
  55.     {
  56.     WORD    state, newstate;
  57.     GRECT    root, ob_rect;
  58.  
  59.     objc_xywh(tree, ROOT, &root);
  60.     state = LWGET(OB_STATE(obj));
  61.     newstate = state ^ SELECTED;
  62.     objc_change(tree, obj, 0, root.g_x, root.g_y, 
  63.         root.g_w, root.g_h, newstate, 1);
  64.     }
  65.  
  66. .bp
  67. VOID                    /* If the object is not already */
  68. objc_sel(tree, obj)            /* SELECTED, make it so.    */
  69.     LONG    tree;
  70.     WORD    obj;
  71.     {
  72.     if ( !(LWGET(OB_STATE(obj)) & SELECTED) )
  73.         objc_toggle(tree, obj);
  74.     }
  75.  
  76.     VOID                /* If the object is SELECTED,    */
  77. objc_dsel(tree, obj)            /* deselect it.            */
  78.     LONG    tree;
  79.     WORD    obj;
  80.     {
  81.     if (LWGET(OB_STATE(obj)) & SELECTED)
  82.         objc_toggle(tree, obj);
  83.     }
  84.  
  85.     VOID                /* Return the object's GRECT      */
  86. objc_xywh(tree, obj, p)            /* through 'p'            */
  87.     LONG    tree;
  88.     WORD    obj;
  89.     GRECT    *p;
  90.     {
  91.     objc_offset(tree, obj, &p->g_x, &p->g_y);
  92.     p->g_w = LWGET(OB_WIDTH(obj));
  93.     p->g_h = LWGET(OB_HEIGHT(obj));
  94.     }
  95. .bp
  96.     VOID                /* Non-cursive traverse of an    */
  97. map_tree(tree, this, last, routine)    /* object tree.  This routine    */
  98.     LONG        tree;        /* is described in PRO GEM #5.    */
  99.     WORD        this, last;
  100.     WORD        (*routine)();
  101.     {
  102.     WORD        tmp1;
  103.  
  104.     tmp1 = this;        /* Initialize to impossible value: */
  105.                 /* TAIL won't point to self!       */
  106.                 /* Look until final node, or off   */
  107.                 /* the end of tree           */ 
  108.     while (this != last && this != NIL)
  109.                 /* Did we 'pop' into this node       */
  110.                 /* for the second time?           */
  111.         if (LWGET(OB_TAIL(this)) != tmp1)
  112.             {
  113.             tmp1 = this;    /* This is a new node       */
  114.             this = NIL;
  115.                     /* Apply operation, testing  */
  116.                     /* for rejection of sub-tree */
  117.             if ((*routine)(tree, tmp1))
  118.                 this = LWGET(OB_HEAD(tmp1));
  119.                     /* Subtree path not taken,   */
  120.                     /* so traverse right         */    
  121.             if (this == NIL)
  122.                 this = LWGET(OB_NEXT(tmp1));
  123.             }
  124.         else            /* Revisiting parent:          */
  125.                     /* No operation, move right  */
  126.             {
  127.             tmp1 = this;
  128.             this = LWGET(OB_NEXT(tmp1));
  129.             }
  130.     }
  131. .bp
  132.     WORD                /* Find the parent object of     */
  133. get_parent(tree, obj)            /* by traversing right until    */
  134.     LONG        tree;        /* we find nodes whose NEXT    */
  135.     WORD        obj;        /* and TAIL links point to     */
  136.     {                /* each other.            */
  137.     WORD        pobj;
  138.  
  139.     if (obj == NIL)
  140.         return (NIL);
  141.     pobj = LWGET(OB_NEXT(obj));
  142.     if (pobj != NIL)
  143.     {
  144.       while( LWGET(OB_TAIL(pobj)) != obj ) 
  145.       {
  146.         obj = pobj;
  147.         pobj = LWGET(OB_NEXT(obj));
  148.       }
  149.     }
  150.     return(pobj);
  151.     } 
  152.  
  153.     WORD
  154. inside(x, y, pt)        /* determine if x,y is in rectangle    */
  155.     WORD        x, y;
  156.     GRECT        *pt;
  157.     {
  158.     if ( (x >= pt->g_x) && (y >= pt->g_y) &&
  159.         (x < pt->g_x + pt->g_w) && (y < pt->g_y + pt->g_h) )
  160.         return(TRUE);
  161.     else
  162.         return(FALSE);
  163.     } 
  164.  
  165.     WORD
  166. rc_intersect(p1, p2)        /* compute intersection of two GRECTs    */
  167.     GRECT        *p1, *p2;
  168.     {
  169.     WORD        tx, ty, tw, th;
  170.  
  171.     tw = min(p2->g_x + p2->g_w, p1->g_x + p1->g_w);
  172.     th = min(p2->g_y + p2->g_h, p1->g_y + p1->g_h);
  173.     tx = max(p2->g_x, p1->g_x);
  174.     ty = max(p2->g_y, p1->g_y);
  175.     p2->g_x = tx;
  176.     p2->g_y = ty;
  177.     p2->g_w = tw - tx;
  178.     p2->g_h = th - ty;
  179.     return( (tw > tx) && (th > ty) );
  180.     }
  181. .bp
  182.     VOID
  183. rc_copy(psbox, pdbox)        /* copy source to destination rectangle    */
  184.     GRECT    *psbox;
  185.     GRECT    *pdbox;
  186.     {
  187.     pdbox->g_x = psbox->g_x;
  188.     pdbox->g_y = psbox->g_y;
  189.     pdbox->g_w = psbox->g_w;
  190.     pdbox->g_h = psbox->g_h;
  191.     }
  192.  
  193. /************* "Hot-spot" manager and subroutines  ***************/
  194.  
  195.     WORD
  196. break_x(pxy)
  197.     WORD    *pxy;
  198.     {                /* Breaking object is right of    */
  199.     if (br_mx < pxy[0])        /* mouse.  Reduce width of     */
  200.         {            /* bounding rectangle.        */
  201.         br_rect.g_w = pxy[0] - br_rect.g_x;
  202.         return (TRUE);
  203.         }
  204.     if (br_mx > pxy[2])        /* Object to left.  Reduce width*/
  205.         {            /* and move rect. to right    */
  206.         br_rect.g_w += br_rect.g_x - pxy[2] - 1;
  207.         br_rect.g_x = pxy[2] + 1;
  208.         return (TRUE);
  209.         }
  210.     return (FALSE);            /* Mouse within object segment.    */
  211.     }                /* Break attempt fails.        */
  212. .bp
  213.     WORD
  214. break_y(pxy)
  215.     WORD    *pxy;
  216.     {
  217.     if (br_my < pxy[1])        /* Object below mouse.  Reduce    */
  218.         {            /* height of bounding rect.    */
  219.         br_rect.g_h = pxy[1] - br_rect.g_y;
  220.         return (TRUE);
  221.         }
  222.     if (br_my > pxy[3])        /* Object above mouse.  Reduce    */
  223.         {            /* height and shift downward.    */
  224.         br_rect.g_h += br_rect.g_y - pxy[3] - 1;
  225.         br_rect.g_y = pxy[3] + 1;
  226.         return (TRUE); 
  227.         }
  228.     /* Emergency escape test! Protection vs. turkeys who nest */
  229.     /* non-selectable objects inside of selectables.          */
  230.     if (br_mx >= pxy[0] && br_mx <= pxy[1])
  231.         {                /* Will X break fail?      */
  232.         br_rect.g_x = br_mx;        /* If so, punt!          */
  233.         br_rect.g_y = br_my;
  234.         br_rect.g_w = br_rect.g_h = 1;
  235.         return (TRUE);
  236.         }
  237.     return (FALSE);
  238.     }
  239. .bp
  240.     WORD
  241. break_obj(tree, obj)            /* Called once per object to    */
  242.     LONG    tree;            /* check if the bounding rect.    */
  243.     WORD    obj;            /* needs to be modified.    */
  244.     {
  245.     GRECT    s;
  246.     WORD    flags, broken, pxy[4];
  247.  
  248.     objc_xywh(tree, obj, &s);
  249.     grect_to_array(&s, pxy);
  250.     if (!rc_intersect(&br_rect, &s))
  251.         return (FALSE);        /* Trivial rejection case     */
  252.  
  253.     flags = LWGET(OB_FLAGS(obj));    /* Is this object a potential    */
  254.     if (flags & HIDETREE)        /* hot-spot?                 */
  255.         return (FALSE);
  256.     if ( !(flags & SELECTABLE) )
  257.         return (TRUE);
  258.     if (LWGET(OB_STATE(obj)) & DISABLED)
  259.         return (TRUE);
  260.  
  261.     for (broken = FALSE; !broken; ) /* This could take two passes     */
  262.         {            /* if the first break fails.       */
  263.         if (br_togl)
  264.             broken = break_x(pxy);
  265.         else
  266.             broken = break_y(pxy);
  267.         br_togl = !br_togl;
  268.         }
  269.     return (TRUE);
  270.     }
  271. .bp
  272.     WORD                /* Manages mouse rectangle events */
  273. form_hot(tree, hot_obj, mx, my, rect, mode)
  274.     LONG    tree;
  275.     WORD    hot_obj, mx, my, *mode;
  276.     GRECT    *rect;
  277.     {
  278.     GRECT    root;
  279.     WORD    state;
  280.  
  281.     objc_xywh(tree, ROOT, &root);    /* If there is already a hot-spot */
  282.     if (hot_obj != NIL)        /* turn it off.              */
  283.         objc_toggle(tree, hot_obj);
  284.  
  285.     if (!(inside(mx, my, &root)) )    /* Mouse has moved outside of       */
  286.         {            /* the dialog.  Wait for return.  */
  287.         *mode = M1_ENTER;
  288.         rc_copy(&root, rect);
  289.         return (NIL);
  290.         }
  291.                     /* What object is mouse over?      */
  292.                     /* (Hit is guaranteed.)           */
  293.     hot_obj = objc_find(tree, ROOT, MAX_DEPTH, mx, my);
  294.                     /* Is this object a hot-spot?      */
  295.     state = LWGET(OB_STATE(hot_obj));
  296.     if (LWGET(OB_FLAGS(hot_obj)) & SELECTABLE)
  297.     if ( !(state & DISABLED) )
  298.         {            /* Yes!  Set up wait state.      */
  299.         *mode = M1_EXIT;
  300.         objc_xywh(tree, hot_obj, rect);
  301.         if (state & SELECTED)    /* But only toggle if it's not      */
  302.             return (NIL);    /* already SELECTED!          */
  303.         else
  304.             {
  305.             objc_toggle(tree, hot_obj);
  306.             return (hot_obj);
  307.             }
  308.         }
  309.  
  310.     rc_copy(&root, &br_rect);    /* No hot object, so compute    */
  311.     br_mx = mx;            /* mouse bounding rectangle.    */
  312.     br_my = my;
  313.     br_togl = 0;
  314.     map_tree(tree, ROOT, NIL, break_obj);
  315.     rc_copy(&br_rect, rect);    /* Then return to wait state.    */
  316.     *mode = M1_EXIT;
  317.     return (NIL);
  318.     }
  319. .bp
  320. /************* Keyboard manager and subroutines ***************/
  321.  
  322.     WORD
  323. find_def(tree, obj)        /* Check if the object is DEFAULT    */
  324.     LONG    tree;
  325.     WORD    obj;
  326.     {            /* Is sub-tree hidden?            */
  327.     if (HIDETREE & LWGET(OB_FLAGS(obj)))
  328.         return (FALSE);
  329.                 /* Must be DEFAULT and not DISABLED    */
  330.     if (DEFAULT & LWGET(OB_FLAGS(obj)))
  331.     if ( !(DISABLED & LWGET(OB_STATE(obj))) )
  332.         fn_obj = obj;    /* Record object number            */
  333.     return (TRUE);
  334.     }
  335.  
  336.     WORD
  337. find_tab(tree, obj)        /* Look for target of TAB operation.    */
  338.     LONG    tree;
  339.     WORD    obj;
  340.     {            /* Check for hiddens subtree.        */
  341.     if (HIDETREE & LWGET(OB_FLAGS(obj)))
  342.         return (FALSE);
  343.                 /* If not EDITABLE, who cares?        */
  344.     if ( !(EDITABLE & LWGET(OB_FLAGS(obj))) )
  345.         return (TRUE);
  346.                 /* Check for forward tab match        */
  347.     if (fn_dir && fn_prev == fn_last)
  348.         fn_obj = obj;
  349.                 /* Check for backward tab match        */
  350.     if (!fn_dir && obj == fn_last)
  351.         fn_obj = fn_prev;
  352.     fn_prev = obj;        /* Record object for next call.        */
  353.     return (TRUE);
  354.     }    
  355.  
  356.     WORD
  357. form_keybd(tree, edit_obj, next_obj, kr, out_obj, okr)
  358.     LONG    tree;
  359.     WORD    edit_obj, next_obj, kr, *out_obj, *okr;
  360.     {
  361.     if (LLOBT(kr))        /* If lower byte valid, mask out    */
  362.         kr &= 0xff;    /* extended code byte.            */
  363.     fn_dir = 0;        /* Default tab direction if backward.    */
  364.     switch (kr) {
  365.         case CR:    /* Zap character.            */
  366.             *okr = 0;
  367.                 /* Look for a DEFAULT object.        */
  368.             fn_obj = NIL;
  369.             map_tree(tree, ROOT, NIL, find_def);
  370.                 /* If found, SELECT and force exit.    */
  371.             if (fn_obj != NIL)
  372.                 {
  373.                 objc_sel(tree, fn_obj);
  374.                 *out_obj = fn_obj;
  375.                 return (FALSE);
  376.                 }        /* Falls through to     */ 
  377.         case TAB:            /* tab if no default     */
  378.         case DOWN:    
  379.             fn_dir = 1;        /* Set fwd direction     */
  380.         case BTAB:
  381.         case UP:
  382.             *okr = 0;        /* Zap character    */
  383.             fn_last = edit_obj;
  384.             fn_prev = fn_obj = NIL; /* Look for TAB object    */
  385.             map_tree(tree, ROOT, NIL, find_tab);
  386.             if (fn_obj == NIL)    /* try to wrap around     */
  387.                 map_tree(tree, ROOT, NIL, find_tab);
  388.             if (fn_obj != NIL)
  389.                 *out_obj = fn_obj;
  390.             break;
  391.         default:            /* Pass other chars    */
  392.             return (TRUE);
  393.         }
  394.     return (TRUE);
  395.     }
  396. .bp
  397. /************* Mouse button manager and subroutines ***************/
  398.  
  399.     WORD
  400. do_radio(tree, obj)
  401.     LONG    tree;
  402.     WORD    obj;
  403.     {
  404.     GRECT    root;
  405.     WORD    pobj, sobj, state;
  406.  
  407.     objc_xywh(tree, ROOT, &root);
  408.     pobj = get_parent(tree, obj);        /* Get the object's parent */
  409.  
  410.     for (sobj = LWGET(OB_HEAD(pobj)); sobj != pobj;
  411.         sobj = LWGET(OB_NEXT(sobj)) )
  412.         {                /* Deselect all but...       */
  413.         if (sobj != obj)
  414.             objc_dsel(tree, sobj);
  415.         }
  416.     objc_sel(tree, obj);            /* the one being SELECTED  */
  417.     }
  418.  
  419.     WORD                    /* Mouse button handler       */
  420. form_button(tree, obj, clicks, next_obj, hot_obj)
  421.     LONG    tree;
  422.     WORD    obj, clicks, *next_obj, *hot_obj;
  423.     {
  424.     WORD    flags, state, hibit, texit, sble, dsbld, edit;
  425.     WORD    in_out, in_state;
  426.  
  427.     flags = LWGET(OB_FLAGS(obj));        /* Get flags and states   */
  428.     state = LWGET(OB_STATE(obj));
  429.     texit = flags & TOUCHEXIT;
  430.     sble = flags & SELECTABLE;
  431.     dsbld = state & DISABLED;
  432.     edit = flags & EDITABLE;
  433.  
  434.     if (!texit && (!sble || dsbld) && !edit) /* This is not an      */
  435.         {                 /* interesting object    */
  436.         *next_obj = 0;
  437.         return (TRUE);
  438.         }
  439.  
  440.     if (texit && clicks == 2)        /* Preset special flag    */
  441.         hibit = 0x8000;
  442.     else
  443.         hibit = 0x0;
  444.  
  445.     if (sble && !dsbld)            /* Hot stuff!        */
  446.         {
  447.         if (flags & RBUTTON)        /* Process radio buttons*/
  448.             do_radio(tree, obj);    /* immediately!        */ 
  449.         else if (!texit)
  450.             {
  451.             in_state = (obj == *hot_obj)?    /* Already toggled ? */
  452.                 state: state ^ SELECTED;    
  453.             if (!graf_watchbox(tree, obj, in_state, 
  454.                 in_state ^ SELECTED))
  455.                 {            /* He gave up...  */
  456.                 *next_obj = 0;
  457.                 *hot_obj = NIL;
  458.                 return (TRUE);
  459.                 }
  460.             }
  461.         else /* if (texit) */
  462.             if (obj != *hot_obj)    /* Force SELECTED    */
  463.                 objc_toggle(tree, obj);
  464.         }
  465.  
  466.     if (obj == *hot_obj)        /* We're gonna do it! So don't    */
  467.         *hot_obj = NIL;        /* turn it off later.        */
  468.  
  469.     if (texit || (flags & EXIT) )    /* Exit conditions.        */
  470.         {
  471.         *next_obj = obj | hibit;
  472.         return (FALSE);        /* Time to leave!        */
  473.         }
  474.     else if (!edit)            /* Clear object unless tabbing    */
  475.         *next_obj = 0;
  476.  
  477.     return (TRUE);
  478.     }
  479. .bp
  480. /************* New forms manager: Entry point and main loop *************/
  481.  
  482.     WORD
  483. form_do(tree, start_fld)
  484.     REG LONG    tree;
  485.     WORD        *start_fld;
  486.     {
  487.     REG WORD    edit_obj;
  488.     WORD        next_obj, hot_obj, hot_mode;
  489.     WORD        which, cont;
  490.     WORD        idx;
  491.     WORD        mx, my, mb, ks, kr, br;
  492.     GRECT        hot_rect;
  493.     WORD        (*valid)();
  494.                         /* Init. editing    */
  495.     next_obj = *start_fld;
  496.     edit_obj = 0;
  497.                         /* Initial hotspot cndx */
  498.     hot_obj = NIL; hot_mode = M1_ENTER;
  499.     objc_xywh(tree, ROOT, &hot_rect);
  500.                         /* Main event loop    */
  501.     cont = TRUE;
  502.     while (cont)
  503.       {
  504.                         /* position cursor on    */
  505.                         /*   the selected     */
  506.                         /*   editting field    */
  507.       if (edit_obj != next_obj)
  508.       if (next_obj != 0)
  509.           {
  510.             edit_obj = next_obj;
  511.             next_obj = 0;
  512.             objc_edit(tree, edit_obj, 0, &idx, EDINIT);
  513.           }
  514.                         /* wait for button or   */
  515.                         /* key or rectangle    */
  516.       which = evnt_multi(MU_KEYBD | MU_BUTTON | MU_M1, 
  517.             0x02, 0x01, 0x01,
  518.             hot_mode, hot_rect.g_x, hot_rect.g_y, 
  519.                 hot_rect.g_w, hot_rect.g_h, 
  520.             0, 0, 0, 0, 0,
  521.             0x0L,
  522.             0, 0,
  523.             &mx, &my, &mb, &ks, &kr, &br);
  524.  
  525.       if (which & MU_M1)            /* handle rect. event     */
  526.           hot_obj = form_hot(tree, hot_obj, mx, my, &hot_rect, &hot_mode);
  527.                         /* handle keyboard event*/
  528.       if (which & MU_KEYBD)
  529.           {                /* Control char filter    */
  530.             cont = form_keybd(tree, edit_obj, next_obj, kr, &next_obj, &kr);
  531.             if (kr && edit_obj)        /* Add others to object    */
  532.             objc_edit(tree, edit_obj, kr, &idx, EDCHAR);
  533.           }
  534.                         /* handle button event    */
  535.       if (which & MU_BUTTON)
  536.           {                /* Which object hit?    */
  537.             next_obj = objc_find(tree, ROOT, MAX_DEPTH, mx, my);
  538.              if (next_obj == NIL)
  539.                   next_obj = 0;
  540.             else                /* Process a click    */
  541.                 cont = form_button(tree, next_obj, br, 
  542.                 &next_obj, &hot_obj);
  543.           }
  544.                         /* handle end of field    */
  545.                         /*   clean up        */
  546.       if (!cont || (next_obj != edit_obj && next_obj != 0))
  547.       if (edit_obj != 0) 
  548.           objc_edit(tree, edit_obj, 0, &idx, EDEND);
  549.       }
  550.                         /* If defaulted, may    */
  551.                         /* need to clear hotspot*/
  552.     if (hot_obj != (next_obj & 0x7fff))
  553.     if (hot_obj != NIL)
  554.         objc_toggle(tree, hot_obj);
  555.                         /* return exit object    */
  556.                         /*   hi bit may be set    */
  557.                         /*   if exit obj. was    */
  558.                         /*   double-clicked    */
  559.     *start_fld = edit_obj;
  560.     return(next_obj);
  561.     }
  562. .!
  563. .!****************************************************************************
  564. .!
  565. .!            End Appendix 10
  566. .!
  567. .!****************************************************************************
  568.